from typing import Any

import requests
from box import Box

from hellchin.assertion.method_assert import BaseMethodAssert


class Undefined:
    def __repr__(self):
        return "undefined"


# 实例化一个特殊对象
UNDEFINED = Undefined()


class AssertionUndefinedError(AssertionError):
    pass

from hellchin.assertion.method_assert import PmMethodAssert

class To:
    """
    To 类，用于创建一个 to 属性，该属性包含一个 BaseMethodAssert 对象，
    """

    def __init__(self, expected_value: Any):
        try:
            self.to = PmMethodAssert(expected_value)
        except Exception as e:
            print("到Expect了", e)
            raise e


class PostManAssert:
    """
    模仿 PM 写的类工具
    """

    def __init__(self):
        # self.expect = Expect  # 初始化Expect对象
        self._response = dict()  # 初始化响应对象
        self.__success_icon = "✅ "
        self.__failure_icon = "❌ "
        self.test_results_list = []  # 初始化结果列表

    @staticmethod
    def _format_assert_error(desc: str, error_message: str) -> str:
        """
        格式化断言错误信息。
        """
        if desc:
            error_message = error_message.split('|')[1]
            return f"❌ {desc} |{error_message}"
        return f"❌ {error_message}"

    @staticmethod
    def test(desc, test_func=None):
        """
        测试方法，用于执行测试函数，并打印测试结果。

        test 方法要对抛出的异常信息做特殊化处理，用来区分硬断言。
        对所有的异常都捕获，因为它们都在test中，不需要在函数外处理
        :param desc:
        :param test_func:
        :return:
        """
        try:
            assert_result = test_func()
            print(f"✅ {desc if desc else assert_result}")

        # 自定义异常类，捕捉 expect(参数) 参数为正确传入的情况
        except AssertionUndefinedError as e:
            print(PostManAssert._format_assert_error(desc, e.args[0].msg))

        except AssertionError as e:
            # 如果断言失败，我们需要处理下断言信息
            print(PostManAssert._format_assert_error(desc, e.args[0].msg))

        except AttributeError as e:
            print("❌ {desc} | {exception_type}: {exception_msg}".format(
                desc=desc,
                exception_type="AssertionError",
                exception_msg=e.args[0]
            ))

        except Exception as e:
            print("⚠️ 未处理的异常错误，请检查: {}".format(e))

    @property
    def response(self):
        """
        获取响应

        此代码的目的是提供一种更灵活的方式来处理不同类型的响应，并且使得对响应的访问更方便。
        简单来说就是对原始 response 对象的访问更加方便，可以通过 response.json() 的方式获取响应的 JSON 数据，
        """

        class ResponseProxy:
            """
            响应代理类，用于处理不同类型的响应

            一个内部类 ResponseProxy。这个类的作用是封装和代理对原始 response 对象的操作，并且提供更灵活的访问。
            """

            def __init__(self, response):
                self._response = response

            def json(self):

                # 判断响应类型
                # 如果响应是 requests.Response 类型，则返回其 json() 方法的结果
                if isinstance(self._response, requests.Response):
                    dict_response = self._response.json()
                # 如果响应是字典类型，则直接返回原始字典
                elif isinstance(self._response, dict):
                    dict_response = self._response
                # 否则抛出异常
                else:
                    raise TypeError(f"Invalid response type: {type(self._response)}")

                # 返回一个 Box 对象，它包含了原始响应字典，并且默认值是 undefined
                return Box(
                    dict_response,
                    default_box=True,  # 是否在访问不存在的键时返回空的 Box 对象
                    default_box_attr=UNDEFINED,  # 不存在的键返回默认值 undefined
                )

            def __getattr__(self, item):
                # 代理其他属性和方法到原始 response 对象
                return getattr(self._response, item)

        return ResponseProxy(self._response)

    @response.setter
    def response(self, value):
        """设置响应"""
        self._response = value

    @staticmethod
    def expect(expected_value: Any):
        """
        预期的值，用于断言

        需要捕获异常信息，处理后返回断言结果，这里是硬断言
        :param expected_value: 预期值
        :return:
        """
        try:
            # 返回To对象，用于使用方法断言实际值
            return To(expected_value)
        except AssertionError as e:
            print(f"expect: ", e)
            return None
        except Exception as e:
            print(f"断言异常！！！检查代码", e)
            return None

if __name__ == '__main__':
    # 封装的pm方法使用
    pm = PostManAssert()

    # 响应的使用
    pm.response = {
        "a": 1,
        "b": 2,
    }

    res = pm.response.json()

    # pm.expect(1).to.equal(2)
    pm.test("", lambda: pm.expect(res.a).to.equal(2))
    pm.test("失败断言", lambda: pm.expect(res.b).to.equal(1))
    pm.test("", lambda: pm.expect(1).to.equal(1))
    pm.test("成功断言", lambda: pm.expect(1).to.equal(1))

    # pm.expect(res.b).to.equal(1)


    # print(pm.response.json().a)
    # print(pm.response.json().b)
    # print(pm.response.json().c)